package com.zy.business.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.zy.business.domain.TbDailyReport;
import com.zy.business.domain.TbDailyReportAnnotate;
import com.zy.business.domain.TbUserDailyReport;
import com.zy.business.mapper.DailyReportAnnotateMapper;
import com.zy.business.mapper.DailyReportMapper;
import com.zy.business.mapper.UserDailyReportMapper;
import com.zy.business.service.DailyReportService;
import com.zy.common.annotation.DataScope;
import com.zy.common.constant.HttpStatus;
import com.zy.common.core.domain.AjaxResult;
import com.zy.common.core.domain.entity.SysDept;
import com.zy.common.core.domain.entity.SysUser;
import com.zy.common.core.page.TableDataInfo;
import com.zy.common.exception.ServiceException;
import com.zy.common.utils.SecurityUtils;
import com.zy.common.utils.*;
import com.zy.system.mapper.SysDeptMapper;
import com.zy.system.mapper.SysUserMapper;
import com.zy.system.service.ISysUserService;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @description: 日报管理接口实现
 * @author: whf
 * @create: 2023-01-13 09:39
 **/
@Service
public class DailyReportServiceImpl extends ServiceImpl<DailyReportMapper, TbDailyReport> implements DailyReportService {

    @Autowired
    private UserDailyReportMapper userDailyReportMapper;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysDeptMapper deptMapper;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private DailyReportAnnotateMapper annotateMapper;

    @Value("${ANNOTATE_NOTICE}")
    private String annotateNoticeId;

    @Value("${APPID}")
    private String APPID;

    @Value("${APPSECRET}")
    private String APPSECRET;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult addDailyReport(TbUserDailyReport userDailyReport) {
        if (userDailyReport.getDailyReportList()==null || userDailyReport.getDailyReportList().size()==0){
            return AjaxResult.error("新增日报失败");
        }
        Boolean verify = this.verify(DateUtils.dateTime(userDailyReport.getReportDate()));
        if (verify){
            throw new ServiceException("当日日报已发布");
        }
        userDailyReportMapper.insert(userDailyReport);
        for (TbDailyReport dailyReport : userDailyReport.getDailyReportList() ) {
            dailyReport.setReportId(userDailyReport.getId());
            dailyReport.setCreateBy(SecurityUtils.getUsername());
            dailyReport.setCreateTime(new Date());
            baseMapper.insert(dailyReport);
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult editDailyReport(TbUserDailyReport userDailyReport) {
        if (userDailyReport.getDailyReportList()==null || userDailyReport.getDailyReportList().size()==0){
            return AjaxResult.error("修改日报失败");
        }
        if (StringUtils.isNotEmpty(userDailyReport.getDelIds())){
            baseMapper.deleteBatchIds(Arrays.asList(userDailyReport.getDelIds().split(",")));
        }
        for (TbDailyReport dailyReport : userDailyReport.getDailyReportList()) {
            if(dailyReport.getId()!=null){
                TbDailyReport old = this.baseMapper.selectById(dailyReport.getId());
                BeanUtils.copyProperties(dailyReport,old);
                old.setUpdateBy(SecurityUtils.getUsername());
                old.setUpdateTime(new Date());
                baseMapper.updateById(old);
            }else {
                dailyReport.setReportId(userDailyReport.getId());
                dailyReport.setCreateBy(SecurityUtils.getUsername());
                dailyReport.setCreateTime(new Date());
                baseMapper.insert(dailyReport);
            }

        }
        return AjaxResult.success();
    }

    @Override
    @DataScope(deptAlias = "d")
    public List<TbUserDailyReport> selectReportList(SysUser user, String reportDate) {
        return baseMapper.selectReportList(user, reportDate);
    }

    @Override
    @DataScope(deptAlias = "d")
    public void exportWord(SysUser user,String reportDate, HttpServletRequest request, HttpServletResponse response) {
        try {
            List<TbUserDailyReport> dailyReports = this.selectReportList(user, reportDate);
            this.exportToWord(dailyReports,"工作日报",request,response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<Map<String, Object>> selectMyData(String month) {
        String firstDay = "";
        String lastDay = "";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        String currentMonth = sdf.format(new Date());
        if(!month.equals(currentMonth)){
            firstDay = DateUtil.giveMonthFist(month);
            lastDay = DateUtil.giveMonthLast(firstDay);
        }else{
            firstDay = DateUtil.giveMonthFist(currentMonth);
            lastDay = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        }
        Long userId = SecurityUtils.getUserId();
        List<Map<String, Object>> mapList = baseMapper.selectMyData(firstDay,lastDay,userId);
        return mapList;
    }

    @Override
    public TableDataInfo reportList(Long deptId, String month) {
        List<Map<String,Object>> dataList = new ArrayList<>();
        String firstDay = "";
        String lastDay = "";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        String currentMonth = sdf.format(new Date());
        if(!month.equals(currentMonth)){
            firstDay = DateUtil.giveMonthFist(month);
            lastDay = DateUtil.giveMonthLast(firstDay);
        }else{
            firstDay = DateUtil.giveMonthFist(currentMonth);
            lastDay = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        }
        SysUser sysUser = new SysUser();
        if (deptId!=null){
            sysUser.setDeptId(deptId);
        }
        sysUser.setIsBoss(0);
        PageUtils.startPage();
        List<SysUser> users = userService.selectUserList(sysUser);
        if (users!=null && users.size()>0){
            for (SysUser user : users) {
                Map<String, Object> dataMap = new HashMap<>();
                dataMap.put("name",user.getName());
                dataMap.put("userId",user.getUserId());
                List<Map<String, Object>> mapList = baseMapper.selectReportByUser(firstDay, lastDay, user.getUserId());
                dataMap.put("holidayList",mapList);
                dataList.add(dataMap);
            }
        }
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(dataList);
        rspData.setTotal(new PageInfo(users).getTotal());
        return rspData;
    }

    @Override
    public List<TbDailyReport> getReportListByProject(String userName, Long projectId, String reportDate) {
        return baseMapper.getReportListByProject(userName,projectId,reportDate);
    }

    @Override
    @Transactional
    public int saveComments(TbDailyReportAnnotate annotate) {
        TbUserDailyReport userDailyReport = userDailyReportMapper.selectById(annotate.getReportId());
        if (userDailyReport.getIsRead()!=2){
            userDailyReport.setIsRead(2);
            userDailyReportMapper.updateById(userDailyReport);
        }
        annotate.setAnnotateTime(new Date());
        int row = annotateMapper.insert(annotate);
        //sendAnnotateNotice(annotate);
        return row;
    }


    private void sendAnnotateNotice(TbDailyReportAnnotate annotate){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        TbUserDailyReport userDailyReport = userDailyReportMapper.selectById(annotate.getReportId());
        SysUser user = userMapper.selectUserById(userDailyReport.getUserId());
        String accessUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APPID+"&secret="+APPSECRET;
        JSONObject result = WebUtil.doGet(accessUrl);
        String accessToken = null;
        if (null != result) {
            accessToken = result.getString("access_token");
        }
        String templtUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+accessToken;

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("touser", user.getOpenId());   // openid
        jsonObject.put("template_id", annotateNoticeId);
        jsonObject.put("url", "http://kq.heshenghua.net/office/#/dailyDetail?openId="+user.getOpenId()+"&reportId="+userDailyReport.getId());
        JSONObject data = new JSONObject();
        JSONObject first = new JSONObject();
        first.put("value", "您有一条日报批注通知");
        first.put("color", "#173177");
        JSONObject keyword1 = new JSONObject();
        keyword1.put("value", sdf.format(userDailyReport.getReportDate()));
        keyword1.put("color", "#173177");
        JSONObject keyword2 = new JSONObject();
        keyword2.put("value", annotate.getAnnotateUser());
        keyword2.put("color", "#173177");
        JSONObject keyword3 = new JSONObject();
        keyword3.put("value", sdf1.format(annotate.getAnnotateContent()) );
        keyword3.put("color", "#173177");
        JSONObject remark = new JSONObject();
        remark.put("value", "点击查看详情");
        remark.put("color", "#173177");
        data.put("first",first);
        data.put("keyword1",keyword1);
        data.put("keyword2",keyword2);
        data.put("keyword3",keyword3);
        data.put("remark",remark);
        jsonObject.put("data", data);

        String string = null;
        try {
            string = WebUtil.sendPostJsonStr(templtUrl, jsonObject.toJSONString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject result1 = JSONObject.parseObject(string);
        int errcode = result1.getIntValue("errcode");
        if(errcode == 0){
            // 发送成功
            System.out.println("发送成功");
        } else {
            // 发送失败
            System.out.println("发送失败");
        }
    }

    @Override
    public AjaxResult changeView(Long id) {
        TbUserDailyReport userDailyReport = userDailyReportMapper.selectById(id);
        userDailyReport.setIsRead(1);
        userDailyReport.setReadUser(SecurityUtils.getUsername());
        userDailyReportMapper.updateById(userDailyReport);
        return AjaxResult.success();
    }

    @Override
    public List<TbUserDailyReport> getMyReportListByDate(String startDate, String endDate) {
        Long userId = SecurityUtils.getUserId();
        return baseMapper.getMyReportListByDate(userId, startDate, endDate);
    }

    @Override
    public Boolean verify(String reportDate) {
        TbUserDailyReport userDailyReport = userDailyReportMapper.selectOne(new QueryWrapper<TbUserDailyReport>().eq("user_id",SecurityUtils.getUserId()).eq("date(report_date)",reportDate));
        if (userDailyReport!=null){
            return true;
        }else {
            return false;
        }
    }

    @Override
    public AjaxResult getReportByDate(Long userId, String date) {
        if (userId==null){
            userId = SecurityUtils.getUserId();
        }
        TbUserDailyReport userDailyReport = userDailyReportMapper.selectOne(new QueryWrapper<TbUserDailyReport>().eq("user_id",userId).eq("report_date",date));
        if (userDailyReport!=null){
            List<TbDailyReport> reportList = baseMapper.getReportByDate(userDailyReport.getId());
            userDailyReport.setDailyReportList(reportList);
            List<TbDailyReportAnnotate> annotateList = annotateMapper.selectList(new QueryWrapper<TbDailyReportAnnotate>().eq("report_id", userDailyReport.getId()).orderByAsc("annotate_time"));
            userDailyReport.setAnnotateList(annotateList);
        }
        return AjaxResult.success(userDailyReport);
    }

    @Override
    public int editComments(TbDailyReportAnnotate annotate) {
        annotate.setUpdateTime(new Date());
        int row = annotateMapper.updateById(annotate);
        return row;
    }

    @Override
    public AjaxResult getDetail(Long reportId) {
        TbUserDailyReport userDailyReport = userDailyReportMapper.selectById(reportId);
        if (userDailyReport!=null){
            List<TbDailyReport> reportList = baseMapper.getReportByDate(userDailyReport.getId());
            userDailyReport.setDailyReportList(reportList);
            List<TbDailyReportAnnotate> annotateList = annotateMapper.selectList(new QueryWrapper<TbDailyReportAnnotate>().eq("report_id", userDailyReport.getId()).orderByAsc("annotate_time"));
            userDailyReport.setAnnotateList(annotateList);
        }
        return AjaxResult.success(userDailyReport);
    }

    public void exportToWord(List<TbUserDailyReport> dailyReports, String title, HttpServletRequest request, HttpServletResponse response) throws IOException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        HashMap<String, ByteArrayOutputStream> fileHashMap = new HashMap<> ();
        // 拼接html格式内容
        if (dailyReports!=null && dailyReports.size()>0){
            for (TbUserDailyReport dailyReport : dailyReports) {
                StringBuffer sbf = new StringBuffer();
                byte[] bs = new byte[1024];
                // 这里拼接一下html标签,便于word文档能够识别
                sbf.append("<html " +
                        "xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:w=\"urn:schemas-microsoft-com:office:word\" xmlns:m=\"http://schemas.microsoft.com/office/2004/12/omml\" xmlns=\"http://www.w3.org/TR/REC-html40\"" + //将版式从web版式改成页面试图
                        ">");
                sbf.append("<head>" +
                        "<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:TrackMoves>false</w:TrackMoves><w:TrackFormatting/><w:ValidateAgainstSchemas/><w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid><w:IgnoreMixedContent>false</w:IgnoreMixedContent><w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText><w:DoNotPromoteQF/><w:LidThemeOther>EN-US</w:LidThemeOther><w:LidThemeAsian>ZH-CN</w:LidThemeAsian><w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript><w:Compatibility><w:BreakWrappedTables/><w:SnapToGridInCell/><w:WrapTextWithPunct/><w:UseAsianBreakRules/><w:DontGrowAutofit/><w:SplitPgBreakAndParaMark/><w:DontVertAlignCellWithSp/><w:DontBreakConstrainedForcedTables/><w:DontVertAlignInTxbx/><w:Word11KerningPairs/><w:CachedColBalance/><w:UseFELayout/></w:Compatibility><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><m:mathPr><m:mathFont m:val=\"Cambria Math\"/><m:brkBin m:val=\"before\"/><m:brkBinSub m:val=\"--\"/><m:smallFrac m:val=\"off\"/><m:dispDef/><m:lMargin m:val=\"0\"/> <m:rMargin m:val=\"0\"/><m:defJc m:val=\"centerGroup\"/><m:wrapIndent m:val=\"1440\"/><m:intLim m:val=\"subSup\"/><m:naryLim m:val=\"undOvr\"/></m:mathPr></w:WordDocument></xml><![endif]-->" +
                        "");

                sbf.append("</head>");
                sbf.append("<body><div>");
                // 列表内容
                sbf.append("<h2 style=\"text-align:center\" >").append(title).append("</h2>");
                if (dailyReport.getDailyReportList()!=null && dailyReport.getDailyReportList().size()>0){
                    SysDept dept = deptMapper.selectDeptById(userMapper.selectUserById(dailyReport.getUserId()).getDeptId());
                    sbf.append("<p>").append("姓名：").append(dailyReport.getUserName()).append("&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;");
                    sbf.append("部门：").append(dept.getDeptName()).append("&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;");
                    sbf.append("日期：").append(sdf.format(dailyReport.getReportDate())).append("</p>");
                    for (TbDailyReport report : dailyReport.getDailyReportList()) {
                        sbf.append("<p>").append("项目：").append(report.getProjectName()).append("</p>");
                        sbf.append("<p>").append("工时：").append(report.getWorkHours()).append("</p>");
                        String content = report.getContent();
                        content = getImgStr(content);
                        sbf.append("<p>").append("内容：").append("<br>").append(content).append("</p>");
                    }
                    sbf.append("</div></body></html>");
                    // 必须要设置编码,避免中文就会乱码
                    byte[] b = sbf.toString().getBytes("GBK");
                    // 将字节数组包装到流中
                    ByteArrayInputStream bais = new ByteArrayInputStream(b);
                    POIFSFileSystem poifs = new POIFSFileSystem();
                    DirectoryEntry dir = poifs.getRoot();
                    dir.createDocument("WordDocument", bais);
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    poifs.writeFilesystem(byteArrayOutputStream);
                    if (byteArrayOutputStream.size() > 0) {
                        fileHashMap.put(dailyReport.getUserName()+sdf.format(dailyReport.getReportDate())+"工作日报.docx",byteArrayOutputStream);
                    }
                    byteArrayOutputStream.flush();
                    byteArrayOutputStream.close();
                }
            }
        }
        if (fileHashMap.size () > 0) {
            byte[] b = this.craeteZipPath(fileHashMap,request,response);
            if (b != null && b.length > 0) {
                ServletOutputStream outputStream = response.getOutputStream ();
                outputStream.write (b);
                outputStream.flush ();
                outputStream.close ();
            }
        }else{
            throw new ServiceException("当天没有成员日报");
        }
    }

    //获取html中的图片元素信息
    public String getImgStr(String htmlStr) {
        Document doc = Jsoup.parse(htmlStr);
        Elements imgs = doc.select("img");
        if (imgs!=null && imgs.size()>0){
            for (Element img : imgs) {
                img.attr("style","");
                img.attr("width","400");
            }
        }
        return doc.toString();
    }


    public byte[] craeteZipPath(HashMap<String, ByteArrayOutputStream> fileMap,HttpServletRequest request,HttpServletResponse response) throws IOException {
        if (fileMap.size() > 0) {
            request.setCharacterEncoding("utf-8");
            String zipName = URLEncoder.encode("成员日报.zip", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename="+zipName);
            response.setContentType("application/msexcel");
            Set<String> mapKey = fileMap.keySet();
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream, Charset.forName("GBK"));
            for (String fileName : mapKey) {
                ByteArrayOutputStream exportFileByteArray = fileMap.get(fileName);
                if (exportFileByteArray.size() > 0) {
                    zipOutputStream.putNextEntry(new ZipEntry(fileName));
                    zipOutputStream.write(exportFileByteArray.toByteArray());
                    zipOutputStream.closeEntry();
                }
            }
            byteArrayOutputStream.flush();
            zipOutputStream.flush();
            zipOutputStream.close();
            byteArrayOutputStream.close();
            return byteArrayOutputStream.toByteArray();
        }
        return null;
    }
}
